home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Mac / scripts / mkapplet.py < prev    next >
Text File  |  1996-01-22  |  7KB  |  301 lines

  1. """Create an applet from a Python script.
  2.  
  3. This puts up a dialog asking for a Python source file ('TEXT').
  4. The output is a file with the same name but its ".py" suffix dropped.
  5. It is created by copying an applet template and then adding a 'PYC '
  6. resource named __main__ containing the compiled, marshalled script.
  7. """
  8.  
  9. DEBUG=0
  10.  
  11. import sys
  12. sys.stdout = sys.stderr
  13.  
  14. import string
  15. import os
  16. import marshal
  17. import imp
  18. import macfs
  19. import MACFS
  20. import MacOS
  21. from Res import *
  22.  
  23. # .pyc file (and 'PYC ' resource magic number)
  24. MAGIC = imp.get_magic()
  25.  
  26. # Template file (searched on sys.path)
  27. TEMPLATE = "PythonApplet"
  28.  
  29. # Specification of our resource
  30. RESTYPE = 'PYC '
  31. RESNAME = '__main__'
  32.  
  33. # A resource with this name sets the "owner" (creator) of the destination
  34. # XXXX Should look for id=0
  35. OWNERNAME = "owner resource"
  36.  
  37. # OpenResFile mode parameters
  38. READ = 1
  39. WRITE = 2
  40.  
  41. def findtemplate():
  42.     """Locate the applet template along sys.path"""
  43.     for p in sys.path:
  44.         template = os.path.join(p, TEMPLATE)
  45.         try:
  46.             template, d1, d2 = macfs.ResolveAliasFile(template)
  47.             break
  48.         except (macfs.error, ValueError):
  49.             continue
  50.     else:
  51.         die("Template %s not found on sys.path" % `TEMPLATE`)
  52.         return
  53.     template = template.as_pathname()
  54.     return template
  55.  
  56. def main():
  57.     global DEBUG
  58.     DEBUG=1
  59.     
  60.     # Find the template
  61.     # (there's no point in proceeding if we can't find it)
  62.     
  63.     template = findtemplate()
  64.     if DEBUG:
  65.         print 'Using template', template
  66.             
  67.     # Ask for source text if not specified in sys.argv[1:]
  68.     
  69.     if not sys.argv[1:]:
  70.         srcfss, ok = macfs.PromptGetFile('Select Python source file:', 'TEXT')
  71.         if not ok:
  72.             return
  73.         filename = srcfss.as_pathname()
  74.         tp, tf = os.path.split(filename)
  75.         if tf[-3:] == '.py':
  76.             tf = tf[:-3]
  77.         else:
  78.             tf = tf + '.applet'
  79.         dstfss, ok = macfs.StandardPutFile('Save application as:', tf)
  80.         if not ok: return
  81.         process(template, filename, dstfss.as_pathname())
  82.     else:
  83.         
  84.         # Loop over all files to be processed
  85.         for filename in sys.argv[1:]:
  86.             process(template, filename, '')
  87.  
  88. def process(template, filename, output):
  89.     
  90.     if DEBUG:
  91.         print "Processing", `filename`, "..."
  92.     
  93.     # Read the source and compile it
  94.     # (there's no point overwriting the destination if it has a syntax error)
  95.     
  96.     fp = open(filename)
  97.     text = fp.read()
  98.     fp.close()
  99.     try:
  100.         code = compile(text, filename, "exec")
  101.     except (SyntaxError, EOFError):
  102.         die("Syntax error in script %s" % `filename`)
  103.         return
  104.     
  105.     # Set the destination file name
  106.     
  107.     if string.lower(filename[-3:]) == ".py":
  108.         destname = filename[:-3]
  109.         rsrcname = destname + '.rsrc'
  110.     else:
  111.         destname = filename + ".applet"
  112.         rsrcname = filename + '.rsrc'
  113.     
  114.     if output:
  115.         destname = output
  116.         
  117.     # Try removing the output file
  118.     try:
  119.         os.unlink(output)
  120.     except os.error:
  121.         pass
  122.         
  123.  
  124.     # Create FSSpecs for the various files
  125.         
  126.     template_fss = macfs.FSSpec(template)
  127.     template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
  128.     dest_fss = macfs.FSSpec(destname)
  129.     
  130.     # Copy data (not resources, yet) from the template
  131.     
  132.     tmpl = open(template, "rb")
  133.     dest = open(destname, "wb")
  134.     data = tmpl.read()
  135.     if data:
  136.         dest.write(data)
  137.     dest.close()
  138.     tmpl.close()
  139.     
  140.     # Open the output resource fork
  141.     
  142.     try:
  143.         output = FSpOpenResFile(dest_fss, WRITE)
  144.     except MacOS.Error:
  145.         if DEBUG:
  146.             print "Creating resource fork..."
  147.         CreateResFile(destname)
  148.         output = FSpOpenResFile(dest_fss, WRITE)
  149.         
  150.     # Copy the resources from the target specific resource template, if any
  151.     typesfound, ownertype = [], None
  152.     try:
  153.         input = FSpOpenResFile(rsrcname, READ)
  154.     except (MacOS.Error, ValueError):
  155.         pass
  156.     else:
  157.         typesfound, ownertype = copyres(input, output, [], 0)
  158.         CloseResFile(input)
  159.         
  160.     # Check which resource-types we should not copy from the template
  161.     skiptypes = []
  162.     if 'SIZE' in typesfound: skiptypes.append('SIZE')
  163.     if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4', 
  164.             'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
  165.     skipowner = (ownertype <> None)
  166.     
  167.     # Copy the resources from the template
  168.     
  169.     input = FSpOpenResFile(template_fss, READ)
  170.     dummy, tmplowner = copyres(input, output, skiptypes, skipowner)
  171.     if ownertype == None:
  172.         ownertype = tmplowner
  173.     CloseResFile(input)
  174.     if ownertype == None:
  175.         die("No owner resource found in either resource file or template")    
  176.     
  177.     # Now set the creator, type and bundle bit of the destination
  178.     dest_finfo = dest_fss.GetFInfo()
  179.     dest_finfo.Creator = ownertype
  180.     dest_finfo.Type = 'APPL'
  181.     dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle
  182.     dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
  183.     dest_fss.SetFInfo(dest_finfo)
  184.     
  185.     # Make sure we're manipulating the output resource file now
  186.     
  187.     UseResFile(output)
  188.     
  189.     # Delete any existing 'PYC ' resource named __main__
  190.     
  191.     try:
  192.         res = Get1NamedResource(RESTYPE, RESNAME)
  193.         res.RemoveResource()
  194.     except Error:
  195.         pass
  196.     
  197.     # Create the raw data for the resource from the code object
  198.     
  199.     data = marshal.dumps(code)
  200.     del code
  201.     data = (MAGIC + '\0\0\0\0') + data
  202.     
  203.     # Create the resource and write it
  204.     
  205.     id = 0
  206.     while id < 128:
  207.         id = Unique1ID(RESTYPE)
  208.     res = Resource(data)
  209.     res.AddResource(RESTYPE, id, RESNAME)
  210.     res.WriteResource()
  211.     res.ReleaseResource()
  212.     
  213.     # Close the output file
  214.     
  215.     CloseResFile(output)
  216.     
  217.     # Give positive feedback
  218.     
  219.     message("Applet %s created." % `destname`)
  220.  
  221.  
  222. # Copy resources between two resource file descriptors.
  223. # skip a resource named '__main__' or (if skipowner is set) 'Owner resource'.
  224. # Also skip resources with a type listed in skiptypes.
  225. #
  226. def copyres(input, output, skiptypes, skipowner):
  227.     ctor = None
  228.     alltypes = []
  229.     UseResFile(input)
  230.     ntypes = Count1Types()
  231.     for itype in range(1, 1+ntypes):
  232.         type = Get1IndType(itype)
  233.         if type in skiptypes:
  234.             continue
  235.         alltypes.append(type)
  236.         nresources = Count1Resources(type)
  237.         for ires in range(1, 1+nresources):
  238.             res = Get1IndResource(type, ires)
  239.             id, type, name = res.GetResInfo()
  240.             lcname = string.lower(name)
  241.             if (type, lcname) == (RESTYPE, RESNAME):
  242.                 continue # Don't copy __main__ from template
  243.             # XXXX should look for id=0
  244.             if lcname == OWNERNAME:
  245.                 if skipowner:
  246.                     continue # Skip this one
  247.                 else:
  248.                     ctor = type
  249.             size = res.size
  250.             attrs = res.GetResAttrs()
  251.             if DEBUG:
  252.                 print id, type, name, size, hex(attrs)
  253.             res.LoadResource()
  254.             res.DetachResource()
  255.             UseResFile(output)
  256.             try:
  257.                 res2 = Get1Resource(type, id)
  258.             except MacOS.Error:
  259.                 res2 = None
  260.             if res2:
  261.                 if DEBUG:
  262.                     print "Overwriting..."
  263.                 res2.RemoveResource()
  264.             res.AddResource(type, id, name)
  265.             res.WriteResource()
  266.             attrs = attrs | res.GetResAttrs()
  267.             if DEBUG:
  268.                 print "New attrs =", hex(attrs)
  269.             res.SetResAttrs(attrs)
  270.             UseResFile(input)
  271.     return alltypes, ctor
  272.  
  273.  
  274. # Show a message and exit
  275.  
  276. def die(str):
  277.     message(str)
  278.     sys.exit(1)
  279.  
  280.  
  281. # Show a message
  282.  
  283. def message(str, id = 256):
  284.     from Dlg import *
  285.     d = GetNewDialog(id, -1)
  286.     if not d:
  287.         print "Error:", `str`
  288.         print "DLOG id =", id, "not found."
  289.         return
  290.     tp, h, rect = d.GetDialogItem(2)
  291.     SetDialogItemText(h, str)
  292.     d.SetDialogDefaultItem(1)
  293.     while 1:
  294.         n = ModalDialog(None)
  295.         if n == 1: break
  296.     del d
  297.  
  298.  
  299. if __name__ == '__main__':
  300.     main()
  301.